﻿using StarryEdge.Core;
using StarryEdge.Core.Device;
using StarryEdge.Core.Enums;
using StarryEdge.Core.Models;
using StarryEdge.Devices.Tool;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StarryEdge.Devices
{
    public abstract class PLCBase
    {
        protected EndianTypes _endianType;
        protected ICommunication _com;
        protected IProtocol _protocol;
        protected IStarryEdgeLog _edgeLog;
        protected Func<DeviceInfoModel, IDevice, bool> _func;

        public PLCBase(ICommunication com, IStarryEdgeLog edgeLog, EndianTypes endianType, Func<DeviceInfoModel, IDevice, bool> func)
        {
            _endianType = endianType;
            _com = com;
            _edgeLog = edgeLog;
            _func = func;
        }

        #region Synchronize
        private volatile int _lock = 0;
        private void Locked()
        {
            int lockNumber = 0;
            while (Interlocked.Exchange(ref _lock, 1) != 0)
            {
                _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0;
                if (++lockNumber > 50)
                {
                    Thread.Sleep(1);
                    lockNumber = 0;
                }
            }
        }

        private void UnLock() => Interlocked.Exchange(ref _lock, 0);
        #endregion
        protected byte[] SendToRead(byte[] bytes, IDevice device, int count = 3)
        {
            for (int i = 0; i < count; i++)
            {
                try
                {
                    Locked();
                    byte[] response = ConnectionHelper.SendToRead(_com, _protocol, bytes, count);
                    UnLock();
                    return response;
                }
                catch (Exception ex)
                {
                    _edgeLog.LogRun($"通信异常：{ex}", Core.Enums.LogLevel.Error);
                    if (_func.Invoke(_com.DeviceInfo, device))
                    {
                        UnLock();
                        return default;
                    }
                    UnLock();
                }
            }
            return default;
        }
    }
}
